package com.lyandwc.lw_bbs.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lyandwc.lw_bbs.entity.*;
import com.lyandwc.lw_bbs.service.*;
import com.lyandwc.lw_bbs.utils.ResponseUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/topics")
public class TopicController {
    private CategoryService categoryService;
    private TopicService topicService;
    private TopicTagService topicTagService;
    private CommentService commentService;
    private NotificationService notificationService;
    private UserService userService;

    public TopicController(CategoryService categoryService, TopicService topicService, TopicTagService topicTagService, CommentService commentService, NotificationService notificationService, UserService userService) {
        this.categoryService = categoryService;
        this.topicService = topicService;
        this.topicTagService = topicTagService;
        this.commentService = commentService;
        this.notificationService = notificationService;
        this.userService = userService;
    }

    @RequestMapping(method = RequestMethod.GET)
    public JSONObject getTopics(
            @RequestParam(name = "categoryId", required = false) Integer categoryId,
            @RequestParam(name = "userId", required = false) Integer userId,
            @RequestParam(name = "tagId", required = false) Integer tagId,
            @RequestParam(name = "page", required = false, defaultValue = "1") int page,
            @RequestParam(name = "limit", required = false, defaultValue = "10") int limit
    ) {
        if (categoryId != null) {
            return ResponseUtils.success(topicService.listTopicsByCategory(categoryId, page, limit));
        } else if (userId != null) {
            return ResponseUtils.success(topicService.listTopicsByUser(userId, page, limit));
        } else if (tagId != null) {
            return ResponseUtils.success(topicService.listTopicsByTag(tagId, page, limit));
        }
        return ResponseUtils.fail("Illegal format params.");
    }

    @PreAuthorize(value = "hasAnyRole('ADMIN', 'USER')")
    @RequestMapping(method = RequestMethod.POST)
    public JSONObject postTopic(
            Authentication authentication,
            @RequestBody Map<String, Object> map
    ) {
        String title = (String) map.get("title");
        Timestamp lastUpdate = new Timestamp(System.currentTimeMillis());
        int categoryId = (int) map.get("categoryId");
        String content = (String) map.get("content");
        int userId = (int) authentication.getCredentials();
        List<Tag> tags = JSONArray.parseArray(JSON.toJSONString(map.get("tags"))).toJavaList(Tag.class);

        Topic topic = new Topic();
        Comment comment = new Comment();
        List<TopicTag> topicTags = new ArrayList<>();

        topic.setTitle(title);
        topic.setLastUpdate(lastUpdate);
        topic.setCategoryId(categoryId);

        comment.setContent(content);
        comment.setCreateAt(lastUpdate);
        comment.setUserId(userId);

        topicService.save(topic);
        comment.setTopicId(topic.getId());
        commentService.save(comment);
        topic.setCommentId(comment.getId());
        topicService.updateById(topic);

        for (Tag tag : tags) {
            TopicTag topicTag = new TopicTag();
            topicTag.setTagId(tag.getId());
            topicTag.setTopicId(topic.getId());
            topicTags.add(topicTag);
        }

        topicTagService.saveBatch(topicTags);

        topic.setComment(comment);
        topic.setTags(tags);

        topicService.updateCount(topic.getId());
        categoryService.updateCount(topic.getCategoryId());
        userService.updateCount(userId);

        return ResponseUtils.success(topic);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public JSONObject getTopic(
            @PathVariable int id
    ) {
        return ResponseUtils.success(topicService.findTopic(id));
    }

    @PreAuthorize(value = "hasAnyRole('ADMIN', 'USER')")
    @RequestMapping(value = "/{id}", method = RequestMethod.POST)
    public JSONObject replyTopic(
            Authentication authentication,
            @PathVariable int id,
            @RequestBody Map<String, String> map
    ) {
        Topic topic = topicService.findTopic(id);
        String content = map.get("content");
        int userId = (int) authentication.getCredentials();

        Comment comment = commentService.insertReplyComment(content, topic.getCommentId(), userId);

        topicService.updateCount(topic.getId());
        categoryService.updateCount(topic.getCategoryId());
        notificationService.addNotification(0, topic.getCommentId(), topic.getComment().getUserId(), comment.getId(), comment.getUserId());
        userService.updateCount(userId);

        return ResponseUtils.success(comment);
    }

    @PreAuthorize(value = "hasAnyRole('ADMIN', 'USER')")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public JSONObject deleteTopic(
            Authentication authentication,
            @PathVariable int id
    ) {
        Topic topic = topicService.findTopic(id);
        int userId = (int) authentication.getCredentials();

        if (topic.getComment().getUserId() != userId) {
            return ResponseUtils.fail("Unauthorized operation.");
        }

        topicService.removeById(id);

        categoryService.updateCount(topic.getCategoryId());
        userService.updateCount(userId);

        return ResponseUtils.success(topic);
    }

    @PreAuthorize(value = "hasAnyRole('ADMIN', 'USER')")
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public JSONObject updateTopic(
            Authentication authentication,
            @PathVariable int id,
            @RequestBody Map<String, Object> map
    ) {
        Topic topic = topicService.findTopic(id);
        int userId = (int) authentication.getCredentials();

        if (topic.getComment().getUserId() != userId) {
            return ResponseUtils.fail("Unauthorized operation.");
        }

        String title = (String) map.get("title");

        if (title != null) {
            topic.setTitle(title);
        }
        topic.setLastUpdate(new Timestamp(System.currentTimeMillis()));

        topicService.updateById(topic);

        String content = (String) map.get("content");

        if (content != null) {
            commentService.updateComment(topic.getCommentId(), content);
        }

        if (map.containsKey("tags")) {
            List<Tag> tags = JSONArray.parseArray(JSON.toJSONString(map.get("tags"))).toJavaList(Tag.class);
            topicTagService.updateTopicTags(topic.getId(), tags);
        }

        return ResponseUtils.success(topicService.findTopic(id));
    }

    @PreAuthorize(value = "hasAnyRole('ADMIN', 'USER')")
    @RequestMapping(value = "/{id}/like", method = RequestMethod.GET)
    public JSONObject likeTopic(
            Authentication authentication,
            @PathVariable int id
    ) {
        Topic topic = topicService.getById(id);
        Comment comment = commentService.likeComment(topic.getCommentId());

        topicService.updateCount(topic.getId());
        categoryService.updateCount(topic.getCategoryId());
        notificationService.addNotification(1, comment.getId(), comment.getUserId(), -1, (int) authentication.getCredentials());

        return ResponseUtils.success(topicService.findTopic(id));
    }
}
